/*
GANESHA - Reasoning on critical infrastructures affected by emergency situations
Copyright (c) 2010-2011, Information Eng. Research Unit - Univ. of Alcala
http://www.cc.uah.es/ie
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 2.1 of the License, or (at your option)
any later version.
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along
with this library; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
package es.uah.cc.ie.ganesha.ontologies;

import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import com.hp.hpl.jena.util.iterator.Filter;
import es.uah.cc.ie.ganesha.GANESHAConfiguration;
import es.uah.cc.ie.ganesha.nodes.NodeInfo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Class that access to the ontology and lets obtain all nodes, domains, and nodes
 * filtered by an specific domain.
 * @author ieru
 */
public class OntologyNodes {

    /**
     * Creates a new instance of this class which directly connects to the ontologies database.
     * @param config GANESHA configuration (needed to know where are the ontologies)
     * @return A new instance of this class which connects to the ontologies database.
     */
    public static OntologyNodes accessOntology(GANESHAConfiguration config) {
        return new OntologyNodes(config);
    }
    
    protected PersistentOntology _ontologies;
    protected GANESHAConfiguration _configuration;
    protected OntModel _ontologyModel;

    /**
     * Constructor
     * @param config GANESHA configuration which specifies all ontologies used by the system.
     */
    protected OntologyNodes(GANESHAConfiguration config) {
        _configuration = config;

        _ontologies = new PersistentOntology(config.getParams(), config.getOntologies(), false);

        _ontologyModel = _ontologies.getOntologyModel();
		_ontologyModel.prepare();
    }
    private static final String NODE_CLASS_URI = "http://www.ieru.org/ont/emergency/BFiaO#Node";
    private static final String DOMAIN_CLASS_URI = "http://www.ieru.org/ont/emergency/BFiaO#Domain";
    private static final String BELONGS_TO_DOMAIN_PROP_URI = "http://www.ieru.org/ont/emergency/BFiaO#belongsToDomain";
    private static final String DOMAIN_HAS_NAME_PROP_URI = "http://www.ieru.org/ont/emergency/BFiaO#hasName";

    /**
     * Returns all nodes in the ontology.
     * @return All nodes in the ontology.
     */
    public List<NodeInfo> getAllNodes() {
        List<NodeInfo> result = new ArrayList<NodeInfo>();

        OntClass nodeClass = _ontologyModel.getOntClass(NODE_CLASS_URI);

		ExtendedIterator<Individual> it = _ontologyModel.listIndividuals(nodeClass);

		if(it != null)
		{
			List<Individual> nodeList = it.toList();

			for (Individual node : nodeList) {
				result.add(this.getInfoFromNode(node));
			}
		}

        return result;
    }

    /**
     * Returns all domains that are available in the ontology.
     * @return Returns all domains in the ontology.
     */
    public List<String> getDomains() {
        List<String> result = new ArrayList<String>();

		OntClass domainClass = _ontologyModel.getOntClass(DOMAIN_CLASS_URI);
		Property nameProperty = _ontologyModel.getDatatypeProperty(DOMAIN_HAS_NAME_PROP_URI);

        List<Individual> domainList = _ontologyModel.listIndividuals(domainClass).toList();

        for(Individual domain : domainList)
        {
			result.add(domain.getPropertyValue(nameProperty).asLiteral().getString());
        }

        return result;
    }

    /**
     * Returns all nodes that belong to a given domain.
     * @param domain Domain of which nodes we expect to receive.
     * @return Returns all nodes that belong to a given domain.
     */
    public List<NodeInfo> getAllNodes(final String domain) {
        List<NodeInfo> result = new ArrayList<NodeInfo>();

        OntClass nodeClass = _ontologyModel.getOntClass(NODE_CLASS_URI);

		final Property belongsToDomainProperty = _ontologyModel.getObjectProperty(BELONGS_TO_DOMAIN_PROP_URI);
		final Property domainNameProperty = _ontologyModel.getDatatypeProperty(DOMAIN_HAS_NAME_PROP_URI);

		Iterator<Individual> filteredNodesIterator = _ontologyModel.listIndividuals(nodeClass).filterKeep(new Filter<Individual>() {

            @Override
            public boolean accept(Individual o) {
				String domainURI = o.getPropertyValue(belongsToDomainProperty).toString();
				Individual domainNode = (Individual) _ontologyModel.getIndividual(domainURI);
				String domainName = domainNode.getPropertyValue(domainNameProperty).asLiteral().getString();

                return domain.equals(domainName);
            }
        });

        for (; filteredNodesIterator.hasNext();) {
            Individual node = filteredNodesIterator.next();

            result.add(getInfoFromNode(node));
        }

        return result;
    }
    private static final String HAS_LOCATION_PROP_URI = "http://www.ieru.org/ont/emergency/BFiaO#hasLocation";
    private static final String HAS_COORDINATE_PROP_URI = "http://www.ieru.org/ont/emergency/BFiaO#hasCoordinate";
    private static final String LAT_PROP_URI = "http://www.ieru.org/ont/emergency/BFiaO#lat";
    private static final String LON_PROP_URI = "http://www.ieru.org/ont/emergency/BFiaO#lon";

    /**
     * Obtains info from a given node in the ongoloty.
     * @param node Individual in the ontology where the info will be obtained from.
     * @return Info from the given node in the ongoloty.
     */
    private NodeInfo getInfoFromNode(Individual node) {
        NodeInfo info = new NodeInfo();

        OntModel ontology = node.getOntModel();

        Property hasLocationProp = ontology.getProperty(HAS_LOCATION_PROP_URI);
        Property hasCoordinateProp = ontology.getProperty(HAS_COORDINATE_PROP_URI);
        Property latProp = ontology.getProperty(LAT_PROP_URI);
        Property lonProp = ontology.getProperty(LON_PROP_URI);

        info.setDomain(getDomainFromNode(node)); //TODO: anyadir informacion real del dominio!!!

        RDFNode hasLocationValue = node.getPropertyValue(hasLocationProp);
        Individual nodeLocation = (Individual) ontology.getIndividual(hasLocationValue.toString());

        RDFNode hasCoordinateValue = nodeLocation.getPropertyValue(hasCoordinateProp);
        Individual nodeCoordinate = (Individual) ontology.getIndividual(hasCoordinateValue.toString());

        info.setLat(nodeCoordinate.getProperty(latProp).getDouble());
        info.setLon(nodeCoordinate.getProperty(lonProp).getDouble());

        info.setName(node.getLocalName());
        info.setId(info.getName());

        return info;
    }

    /**
     * Obtains a descriptive string from the node domain.
     * @param node Node to be checked.
     * @return Descriptive string from the node domain.
     */
    private String getDomainFromNode(Individual node) {
        final Property belongsToDomainProperty = _ontologyModel.getObjectProperty(BELONGS_TO_DOMAIN_PROP_URI);
		final Property domainNameProperty = _ontologyModel.getDatatypeProperty(DOMAIN_HAS_NAME_PROP_URI);

		String domainURI = node.getPropertyValue(belongsToDomainProperty).toString();
		Individual domainNode = (Individual) _ontologyModel.getIndividual(domainURI);
		String domainName = domainNode.getPropertyValue(domainNameProperty).asLiteral().getString();

        return domainName;
    }
}
